package maps

func Get[M ~map[K]V, K comparable, V any](m M, k K) (v V, ok bool) {
	if len(m) == 0 {
		return
	}
	v, ok = m[k]
	return
}

func GetPtr[M ~map[K]*V, K comparable, V any](m M, k K) (v *V) {
	if len(m) == 0 {
		return
	}
	var ok bool
	v, ok = m[k]
	if !ok || v == nil {
		return nil
	}
	return
}

func Set[M ~map[K]V, K comparable, V any](m M, k K, v V) {
	if m == nil {
		return
	}
	m[k] = v
}

func SetPtr[M ~map[K]*V, K comparable, V any](m M, k K, v *V) {
	if m == nil {
		return
	}
	if v == nil {
		return
	}
	m[k] = v
}

func Delete[M ~map[K]V, K comparable, V any](m M, ks ...K) {
	if len(m) == 0 {
		return
	}
	for _, k := range ks {
		delete(m, k)
	}
}

func DeleteFunc[M ~map[K]V, K comparable, V any](m M, f func(k K, v V) (deleted, continued bool)) {
	if len(m) == 0 {
		return
	}
	if f == nil {
		return
	}
	var d, c bool
	for k, v := range m {
		d, c = f(k, v)
		if d {
			delete(m, k)
		}
		if !c {
			break
		}
	}
}

func Exists[M ~map[K]V, K comparable, V any](m M, k K) (ok bool) {
	if len(m) == 0 {
		return
	}
	_, ok = m[k]
	return
}

func All[M ~map[K]V, K comparable, V any](m M, ks ...K) bool {
	if len(m) == 0 {
		return false
	}
	for _, k := range ks {
		if _, ok := m[k]; !ok {
			return false
		}
	}
	return true
}

func Each[M ~map[K]V, K comparable, V any](m M, f func(k K, v V) (continued bool)) {
	if len(m) == 0 {
		return
	}
	if f == nil {
		return
	}
	for k, v := range m {
		if !f(k, v) {
			break
		}
	}
}

func Len[M ~map[K]V, K comparable, V any](m M) int {
	return len(m)
}

func Clear[M ~map[K]V, K comparable, V any](m M) {
	if len(m) == 0 {
		return
	}
	for k := range m {
		delete(m, k)
	}
}

func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
	if len(m1) != len(m2) {
		return false
	}
	for k, v1 := range m1 {
		if v2, ok := m2[k]; !ok || v1 != v2 {
			return false
		}
	}
	return true
}

func EqualFunc[M ~map[K]V, K comparable, V any](m1, m2 M, f func(v1 V, v2 V) bool) bool {
	if len(m1) != len(m2) {
		return false
	}
	for k, v1 := range m1 {
		if v2, ok := m2[k]; !ok || (f != nil && !f(v1, v2)) {
			return false
		}
	}
	return true
}

func Clone[M ~map[K]V, K comparable, V any](m M) M {
	if m == nil {
		return nil
	}
	n := make(M, len(m))
	for k, v := range m {
		n[k] = v
	}
	return n
}

func Copy[M ~map[K]V, K comparable, V any](src, dest M) {
	for k, v := range src {
		dest[k] = v
	}
}
